"""工具函数模块"""
import redis
from fastapi import HTTPException
from contextlib import asynccontextmanager
from fastapi import FastAPI
from .config import REDIS_CONFIG, logger
import re

# Redis客户端
redis_client = None

# 交易所映射表
EXCHANGE_MAP = {
    # 郑商所品种
    'AP': 'CZCE',  # 苹果
    'CF': 'CZCE',  # 棉花
    'CY': 'CZCE',  # 棉纱
    'FG': 'CZCE',  # 玻璃
    'JR': 'CZCE',  # 粳稻
    'LR': 'CZCE',  # 晚籼稻
    'MA': 'CZCE',  # 甲醇
    'OI': 'CZCE',  # 菜油
    'PM': 'CZCE',  # 普麦
    'RI': 'CZCE',  # 早籼稻
    'RM': 'CZCE',  # 菜粕
    'RS': 'CZCE',  # 菜籽
    'SA': 'CZCE',  # 纯碱
    'SF': 'CZCE',  # 硅铁
    'SM': 'CZCE',  # 锰硅
    'SR': 'CZCE',  # 白糖
    'TA': 'CZCE',  # PTA
    'WH': 'CZCE',  # 强麦
    'ZC': 'CZCE',  # 动力煤
    
    # 大商所品种
    'a': 'DCE',   # 豆一
    'b': 'DCE',   # 豆二
    'c': 'DCE',   # 玉米
    'cs': 'DCE',  # 淀粉
    'i': 'DCE',   # 铁矿石
    'j': 'DCE',   # 焦炭
    'jd': 'DCE',  # 鸡蛋
    'jm': 'DCE',  # 焦煤
    'l': 'DCE',   # 塑料
    'm': 'DCE',   # 豆粕
    'p': 'DCE',   # 棕榈油
    'pp': 'DCE',  # PP
    'v': 'DCE',   # PVC
    'y': 'DCE',   # 豆油
    
    # 上期所品种
    'ag': 'SHFE',  # 白银
    'al': 'SHFE',  # 铝
    'au': 'SHFE',  # 黄金
    'bu': 'SHFE',  # 沥青
    'cu': 'SHFE',  # 铜
    'fu': 'SHFE',  # 燃油
    'hc': 'SHFE',  # 热轧卷板
    'ni': 'SHFE',  # 镍
    'pb': 'SHFE',  # 铅
    'rb': 'SHFE',  # 螺纹钢
    'ru': 'SHFE',  # 橡胶
    'sn': 'SHFE',  # 锡
    'wr': 'SHFE',  # 线材
    'zn': 'SHFE',  # 锌
}

@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    global redis_client
    try:
        redis_client = redis.Redis(**REDIS_CONFIG)
        redis_client.ping()
        logger.info(f"Connected to Redis at {REDIS_CONFIG['host']}:{REDIS_CONFIG['port']}")
        yield
    except Exception as e:
        logger.error(f"Failed to connect to Redis: {e}")
        if redis_client:
            redis_client.close()
        raise
    finally:
        if redis_client:
            redis_client.close()
            logger.info("Disconnected from Redis")

def check_redis():
    """检查Redis连接状态"""
    if not redis_client:
        raise HTTPException(
            status_code=503,
            detail="Redis connection not available"
        )
    try:
        redis_client.ping()
    except Exception as e:
        logger.error(f"Redis connection error: {e}")
        raise HTTPException(
            status_code=503,
            detail="Redis connection error"
        )

def get_exchange_by_code(code: str) -> str:
    """根据合约代码获取交易所代码
    
    Args:
        code: 合约代码(如: SA501, au2306)
    
    Returns:
        str: 交易所代码
    
    Raises:
        ValueError: 无法识别的合约代码
    """
    if not code:
        raise ValueError("Empty contract code")
        
    # 移除所有空白字符
    code = code.strip()
    
    # 提取合约前缀（字母部分）
    match = re.match(r'^([A-Za-z]+)', code)
    if not match:
        raise ValueError("Invalid contract code format")
    
    prefix = match.group(1)
    # 先尝试直接匹配
    if prefix in EXCHANGE_MAP:
        return EXCHANGE_MAP[prefix]
    
    # 尝试大写匹配
    prefix_upper = prefix.upper()
    if prefix_upper in EXCHANGE_MAP:
        return EXCHANGE_MAP[prefix_upper]
        
    # 尝试小写匹配
    prefix_lower = prefix.lower()
    if prefix_lower in EXCHANGE_MAP:
        return EXCHANGE_MAP[prefix_lower]
    
    raise ValueError(f"Unknown contract prefix: {prefix}")

def normalize_czce_code(code: str) -> str:
    """标准化郑商所合约代码
    
    郑商所合约代码有两种格式：
    1. 3位数字（如：501）- 需要补充年份
    2. 4位数字（如：2501）- 完整年份
    
    Args:
        code: 原始合约代码
    
    Returns:
        str: 标准化后的合约代码
    """
    # 提取字母和数字部分
    match = re.match(r'^([A-Za-z]+)([0-9]+)$', code)
    if not match:
        return code
        
    prefix, number = match.groups()
    
    # 如果是3位数字，补充年份2
    if len(number) == 3:
        number = '2' + number
        
    return prefix + number

def parse_symbol(symbol: str) -> tuple[str, str]:
    """解析合约代码
    
    Args:
        symbol: 合约代码，支持两种格式：
               1. EXCHANGE:CODE (如: SHFE:au2306)
               2. CODE (如: SA501，将自动识别交易所)
    
    Returns:
        tuple[str, str]: (交易所代码, 合约代码)
    
    Raises:
        HTTPException: 格式错误时抛出400错误
    """
    try:
        if not symbol:
            raise ValueError("Empty symbol")
            
        # 移除所有空白字符
        symbol = symbol.strip()
        
        # 检查是否包含交易所代码
        if ':' in symbol:
            parts = symbol.split(':')
            if len(parts) != 2:
                raise ValueError("Invalid symbol format: too many colons")
            exchg, code = parts
            exchg = exchg.strip().upper()  # 标准化交易所代码
            code = code.strip()            # 移除空白字符
            
            if not exchg:
                raise ValueError("Exchange code is empty")
            if not code:
                raise ValueError("Contract code is empty")
                
            # 验证交易所代码
            valid_exchanges = {'CZCE', 'DCE', 'SHFE'}
            if exchg not in valid_exchanges:
                raise ValueError(f"Invalid exchange code: {exchg}")
        else:
            # 自动识别交易所
            code = symbol
            exchg = get_exchange_by_code(code)
        
        # 验证合约代码基本格式
        if not re.match(r'^[A-Za-z]+[0-9]+$', code):
            raise ValueError("Invalid contract code format")
            
        # 对郑商所合约进行特殊处理
        if exchg == 'CZCE':
            code = normalize_czce_code(code)
        
        return exchg, code
    
    except Exception as e:
        logger.error(f"Symbol parsing error: {str(e)} for symbol: {symbol}")
        raise HTTPException(
            status_code=400,
            detail=f"Invalid symbol format: {str(e)}. Expected format: EXCHANGE:CODE or valid contract code"
        ) 